﻿// // ******************************************************************
// //       /\ /|       @file       TranslateBackgroundService.cs
// //       \ V/        @brief      await29
// //       | "")       @author     Await, 285283010@qq.com
// //       /  |
// //      /  \\        @Modified   2025-03-01 09:03
// //    *(__\_\        @Copyright  Copyright (c) , 2025-01-03 19:01 Await
// // ******************************************************************

using System.Collections.Concurrent;
using System.Threading.Channels;
using AutomaticSubtitles.Service.Application.Language.Queries;
using AutomaticSubtitles.Service.Application.Media.Queries;
using AutomaticSubtitles.Service.Application.Translate.Service.Commands;
using AutomaticSubtitles.Service.DataAccess.Model;

namespace AutomaticSubtitles.Service.BackgroundServices;

/// <summary>
/// 后台翻译服务
/// </summary>
/// <param name="serviceProvider"></param>
public class TranslateBackgroundService(IServiceProvider serviceProvider, RedisClient redisClient) : BackgroundService
{
    private static Channel<Auto_Media> _mediaChannel = Channel.CreateUnbounded<Auto_Media>();
    private static ConcurrentBag<Auto_Media> mediaChannel = new();
    private IEventBus _eventBus;

    private ILogger<TranslateBackgroundService> _logger;

    private static bool IsRunning               { get; set; }
    private static bool IsWantToDoItImmediately { get; set; }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using var serviceScope = serviceProvider.CreateScope();
        _logger = serviceScope.ServiceProvider.GetService<ILogger<TranslateBackgroundService>>()!;
        _eventBus = serviceScope.ServiceProvider.GetService<IEventBus>()!;
        _logger.LogWarning("--后台自动翻译任务 开启");
        Init();
        _ = Receiving();
        Task.Factory.StartNew(async () => { await PriorityTasks(stoppingToken); }, stoppingToken);

        IsRunning = true;

        // 使用 TaskCompletionSource 更好地控制任务生命周期
        var taskCompletionSource = new TaskCompletionSource<bool>();

        await Task.Run(async () =>
        {
            try
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    if (!IsRunning && !IsWantToDoItImmediately) //TODO:需要添加手动触发更新任务
                        // if (IsRunning || !WhetherToExecuteTheTask()) //TODO:需要添加手动触发更新任务
                    {
                        //5分钟一次
                        await Task.Delay(20000, stoppingToken);
                        // await Task.Delay(5 * 1000 * 60, stoppingToken);
                        continue;
                    }

                    IsRunning = true;
                    try
                    {
                        if (!IsWantToDoItImmediately)
                            if (!WhetherToExecuteTheTask())
                            {
                                await Task.Delay(10000, stoppingToken);
                                continue;
                            }

                        if (IsWantToDoItImmediately) IsWantToDoItImmediately = false;
                        _logger.LogInformation("--更新翻译数据任务 开始");
                        await RunTask();
                        var dateTime = DateTime.Now;
                        await redisClient.SetAsync(CacheCommon.TranslationTask, dateTime);
                        _logger.LogInformation("--更新翻译数据任务 结束");
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e, "--更新翻译数据任务 异常");
                    }
                    finally
                    {
                        IsRunning = false;
                    }
                }

                taskCompletionSource.SetResult(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "后台任务异常");
                taskCompletionSource.SetException(ex);
            }
        }, stoppingToken);

        // 等待任务完成或发生异常
        await taskCompletionSource.Task;
    }

    /// <summary>
    /// 初始化人工任务数据提交
    /// </summary>
    private void Init()
    {
        redisClient.Subscribe(CacheCommon.TranslateBackgroundServiceKey, async (_, x) =>
        {
            //
            if (x is not nameof(TranslateBackgroundService)) return;
            _logger.LogWarning("--自动翻译 收到缓存更新通知");
            IsWantToDoItImmediately = true;
        });
    }

    /// <summary>
    ///     判断上一次执行任务时长
    /// </summary>
    /// <returns></returns>
    private bool WhetherToExecuteTheTask()
    {
        var dateTime = redisClient.Get<DateTime?>(CacheCommon.TranslationTask);
        if (dateTime == null) return true;
        var time = DateTime.Now;
        return time.Subtract(dateTime.Value).TotalMinutes > 30;
    }

    /// <summary>
    /// 运行任务
    /// </summary>
    private async Task RunTask()
    {
        var getCacheKeyDataQuery = await GetTranslationType();
        if (getCacheKeyDataQuery == null) return;
        var obtainTranslationMediaQuery = new ObtainTranslationMediaQuery(getCacheKeyDataQuery);
        await _eventBus.PublishAsync(obtainTranslationMediaQuery);
        if (obtainTranslationMediaQuery.Result is not { Count: not 0 } && obtainTranslationMediaQuery.MVResult is not { Count: not 0 })
        {
            _logger.LogWarning("--没有需要翻译的媒体");
            return;
        }

        var isRun = false;
        var isMvRun = false;
        if (obtainTranslationMediaQuery.Result != null)
        {
            foreach (var msg in obtainTranslationMediaQuery.Result.Select(keyValuePair => $"--电视剧:{keyValuePair.Key} 需要翻译{keyValuePair.Value.Count}集")) _logger.LogWarning(msg);

            isRun = true;
        }

        if (obtainTranslationMediaQuery.MVResult != null)
        {
            foreach (var msg in obtainTranslationMediaQuery.MVResult.Select(keyValuePair => $"--电影:{keyValuePair.Key} 需要翻译{keyValuePair.Value.Count}部")) _logger.LogWarning(msg);

            isMvRun = true;
        }

        if (!isMvRun && !isRun) return;
        var mvLen = 0;
        var tvLen = 0;
        _logger.LogWarning("----------------------------------------------------------------\r\n");

        if (obtainTranslationMediaQuery.Result != null)
        {
            var sub = new SubtitleTranslationCommand(obtainTranslationMediaQuery.Result);
            await _eventBus.PublishAsync(sub);
            if (sub.Result != null)
            {
                tvLen = sub.Result.Count;
                foreach (var item in sub.Result) _logger.LogWarning($"--翻译文件：{item}");
            }
        }

        if (obtainTranslationMediaQuery.MVResult != null)
        {
            var subMV = new SubtitleTranslationCommand(obtainTranslationMediaQuery.MVResult);
            await _eventBus.PublishAsync(subMV);
            if (subMV.Result != null)
            {
                mvLen = subMV.Result.Count;
                foreach (var item in subMV.Result) _logger.LogWarning($"--翻译文件：{item}");
            }
        }

        _logger.LogWarning($"--电视剧翻译结果：{tvLen}集");
        _logger.LogWarning($"--电影翻译结果：{mvLen}部");

        _logger.LogWarning("\r\n----------------------------------------------------------------");
    }

    /// <summary>
    /// 获取翻译类型
    /// </summary>
    /// <returns></returns>
    private async Task<Dictionary<string, bool>?> GetTranslationType()
    {
        var getCacheKeyDataQuery = new GetLanguageKeyDataQuery();
        await _eventBus.PublishAsync(getCacheKeyDataQuery);
        if (getCacheKeyDataQuery.Result != null) return getCacheKeyDataQuery.Result;
        _logger.LogWarning("--未配置需要翻译的语言");
        return null;
    }

    #region 优先翻译

    /// <summary>
    /// 优先翻译任务
    /// </summary>
    /// <param name="stoppingToken"></param>
    private async Task PriorityTasks(CancellationToken stoppingToken)
    {
        _logger.LogWarning("--开启优先翻译服务 开始");
        while (!stoppingToken.IsCancellationRequested)
            try
            {
                if (mediaChannel.IsEmpty) //TODO:需要添加手动触发更新任务
                {
                    await Task.Delay(20000, stoppingToken);
                    continue;
                }

                _logger.LogWarning("--检测到需要优先翻译媒体 开始");
                // 优先翻译文件
                var data = new List<Auto_Media>();
                while (mediaChannel.TryTake(out var item))
                    if (!data.Exists(x => x.Id == item.Id))
                        data.TryAdd(item);
                await StartPrioritizingTranslationTask(data);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "--优先翻译任务异常");
            }

        _logger.LogWarning("--开启优先翻译服务 结束");
    }

    /// <summary>
    /// 开始优先处理翻译任务
    /// </summary>
    /// <param name="data"></param>
    private async Task StartPrioritizingTranslationTask(List<Auto_Media> data)
    {
        if (data.Count == 0) return;
        var translationType = await GetTranslationType();
        if (translationType == null) return;
        var obtainTranslationMediaToDataQuery = new ObtainTranslationMediaToDataQuery(translationType, data);
        await _eventBus.PublishAsync(obtainTranslationMediaToDataQuery);
        if (obtainTranslationMediaToDataQuery.Result != null)
        {
            var sub = new SubtitleTranslationCommand(obtainTranslationMediaToDataQuery.Result);
            await _eventBus.PublishAsync(sub);
            if (sub.Result != null)
                foreach (var item in sub.Result)
                    _logger.LogWarning($"--翻译文件：{item}");
        }

        if (obtainTranslationMediaToDataQuery.MVResult != null)
        {
            var subMV = new SubtitleTranslationCommand(obtainTranslationMediaToDataQuery.MVResult);
            await _eventBus.PublishAsync(subMV);
            if (subMV.Result != null)
                foreach (var item in subMV.Result)
                    _logger.LogWarning($"--翻译文件：{item}");
        }
    }

    private static async Task Receiving()
    {
        await foreach (var item in _mediaChannel.Reader.ReadAllAsync()) mediaChannel.Add(item);
    }

    /// <summary>
    /// 添加后台翻译 优先服务
    /// </summary>
    /// <param name="data"></param>
    public static void AddTranslateMedia(Auto_Media data)
    {
        _mediaChannel.Writer.TryWrite(data);
    }

    #endregion
}